package com.atguigu.es;

import com.atguigu.es.vo.Product;
import com.google.gson.Gson;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

//@SpringBootTest
public class Demo02EsRestTemplate {
    @Autowired
    ElasticsearchRestTemplate restTemplate;


    /*
        复杂查询：
            操作的是es中存储的atguigu索引数据，数据类型比较复杂
            根据es中的数据创建数据模型
            { "title":"华为nova手机",
             "images":"http://image.jd.com/12479122.jpg",
             "price":2999,
             "stock": 300,
             "attr":
                {
                "category": "手机",
                "brand": "华为"
                }
            }
     */
    @Test
    void testQuery(){
        //builder用来构建查询的条件
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //匹配查询：title中包含小米手机
        builder.withQuery(QueryBuilders.matchQuery("title","小米手机"));
        //模糊查询：Fuzziness.TWO指定偏差量为2，如果更新两次可以变为小米，文档就可以匹配
        //默认偏差量为1
//        builder.withQuery(QueryBuilders.fuzzyQuery("title","小米").fuzziness(Fuzziness.TWO));
        //布尔查询
//        builder.withQuery(QueryBuilders.boolQuery()
//                .must(QueryBuilders.termsQuery("attr.brand.keyword" , "小米"))
//                .must(QueryBuilders.rangeQuery("price").lte(3999).gte(1999)));
        //分页查询
//        builder.withPageable(PageRequest.of(1,5));
        //过滤查询的属性字段
//        builder.withFields("id" , "title" , "price" , "attr.category");
        //高亮查询
        builder.withHighlightBuilder(new HighlightBuilder()
                    .field("title").preTags("<em>").postTags("</em>"));

        //聚合查询： 使用品牌聚合为桶，桶内再次使用分类聚合为桶，在分类桶中进行度量统计平均价格
        builder.addAggregation(AggregationBuilders.terms("品牌").field("attr.brand.keyword")
                            .subAggregation(AggregationBuilders.terms("分类")
                                    .field("attr.category.keyword")
                                    .subAggregation(AggregationBuilders.avg("分类平均价格").field("price"))
                            )
                            );
        //发起查询
        SearchHits<Product> search = restTemplate.search(builder.build(), Product.class);
        //解析结果集
        search.getSearchHits().forEach(searchHit->{
            Product p = searchHit.getContent();
            //每解析一个文档时，获取它的高亮字段
            List<String> titles = searchHit.getHighlightField("title");
//            System.out.println("高亮字段: "+titles);
            //将高亮字段的值设置给数据源
            if(!CollectionUtils.isEmpty(titles)){
                 p.setTitle(titles.get(0));
            }
            System.out.println(p);
        });
        //解析桶
        //根据桶的名称从查询到的json中获取最外层的桶内容
        //聚合时：结果有可能是分组结果 也有可能是统计结果
        ParsedStringTerms brands = search.getAggregations().get("品牌");
//        System.out.println(brands.getClass().getName());
        System.out.println("最外层桶名："+ brands.getName());
        brands.getBuckets().forEach(bucket->{
            System.out.println(brands.getName()+":  "+  bucket.getKey()+" , "+ bucket.getDocCount());
            ParsedStringTerms cates = bucket.getAggregations().get("分类");
            cates.getBuckets().forEach(cate->{
                System.out.println(cate.getKey()+" , "+ cate.getDocCount());
                ParsedAvg avgPrice = cate.getAggregations().get("分类平均价格");
                System.out.println(avgPrice.getValue());
                System.out.println(avgPrice.getName());
                System.out.println("===================================");
            });
        });
    }

    @Autowired
    RestHighLevelClient restHighLevelClient;
    Gson gson = new Gson();
    @Test
    public void testHighLevelClient() throws IOException {
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchQuery("title","华为手机"));
        sourceBuilder.highlighter(new HighlightBuilder().field("title")
                .preTags("<b style='color:red;'>").postTags("</b>"));
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = search.getHits().getHits();
        for (SearchHit hit : hits) {
//            System.out.println(hit.getSourceAsString());
            Product product = gson.fromJson(hit.getSourceAsString(), Product.class);
            product.setId(Long.parseLong(hit.getId()));
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlightField = highlightFields.get("title");
            product.setTitle(Arrays.toString(highlightField.getFragments()));
            System.out.println(product);



        }
    }




}
